# coding=utf-8

import queue
import logging
from logging.handlers import QueueHandler, QueueListener
from logging import Logger
import uuid
from flask import current_app

from app.extensions import db
from app.models import Dispatcher


class MemoryStringHandler(logging.Handler):
    """将日志信息保存在内存中"""
    def __init__(self, level=logging.NOTSET):
        super().__init__(level=level)
        self.string_buffer = ''

    def emit(self, record):
        self.string_buffer += self.format(record=record) + '\n'

    def close(self):
        super().close()
        self.string_buffer = ''


class DispatcherLogDBHandler(logging.Handler):
    """将日志信息保存在Dispatcher表中"""
    def __init__(self, dispatcher_id, level=logging.NOTSET):
        super().__init__(level=level)
        self.dispatcher_id = dispatcher_id
        self.app = current_app._get_current_object()  # 获取被代理的真实对象,
        # self.app 用于在队列线程中使用app实例提供的上下文(当该handler结合QueueHandler使用时)

    def emit(self, record):
        # 强制读取最新结果(从__init__到emit,这期间同一条数据被修改,如果这里不使用db.session.commit()，
        # 则取self.dispatcher.log数值将不会从数据库更新，获取依然是__init__中查询到的数据)
        with self.app.app_context():
            db.session.commit()
            dispatcher = Dispatcher.query.filter_by(id=self.dispatcher_id).first()
            dispatcher.log += self.format(record=record) + '\n'
            db.session.commit()


# class CaseDispatcherLogger:
class DispatcherLogger:
    def __init__(self,
                 use_memory_string_handler=True,
                 use_dispatcher_log_db_handler=False,
                 use_queue_handler=True,
                 dispatcher_id=None):
        """
        创建调度日志
        :param use_memory_string_handler: 仅使用MemoryStringHandler(), 一般用于单独执行case
        :param use_dispatcher_log_db_handler: 仅使用DispatcherLogDBHandler(), 将调度日志写入数据库中
        :param use_queue_handler: 是否使用QueueHandler QueueListener将handler放入异步队列完成日志记录
        :param dispatcher_id: 当use_dispatcher_log_db_handler为True时需要指定调度编号，调度日志将写入该条调度数据
        """
        if not any([use_memory_string_handler, use_dispatcher_log_db_handler]):
            raise ValueError('参数use_memory_string_handler与参数use_dispatcher_log_db_handler不能同时为False')
        self.use_memory_string_handler = use_memory_string_handler
        self.use_queue_handler = use_queue_handler

        formatter = logging.Formatter('[%(levelname)s %(asctime)s]:%(message)s')
        self.name = str(uuid.uuid1())
        self.logger = logging.getLogger(self.name)
        self.logger.propagate = False  # 记录消息将不会传递给当前记录器的祖先记录器的处理器

        handlers = []
        if use_memory_string_handler:
            self.memory_string_handler = MemoryStringHandler()
            self.memory_string_handler.setFormatter(formatter)
            handlers.append(self.memory_string_handler)
        if use_dispatcher_log_db_handler:
            if dispatcher_id is None:
                raise ValueError('参数use_dispatcher_log_db_handler为True时必须指定dispatcher_id, 当前为None')
            self.dispatcher_log_db_handler = DispatcherLogDBHandler(dispatcher_id)
            self.dispatcher_log_db_handler.setFormatter(formatter)
            handlers.append(self.dispatcher_log_db_handler)

        if self.use_queue_handler:
            self.queue = queue.Queue(-1)
            self.queue_handler = QueueHandler(self.queue)
            self.logger.addHandler(self.queue_handler)
            self.listener = QueueListener(self.queue, *handlers, respect_handler_level=True)
            self.listener.start()
        else:
            for handler in handlers:
                self.logger.addHandler(handler)

    def clear_string_buffer(self):
        if self.use_memory_string_handler:
            self.memory_string_handler.string_buffer = ''

    def get_string_buffer(self):
        if self.use_memory_string_handler:
            return self.memory_string_handler.string_buffer

    def close(self):
        if self.use_queue_handler:
            self.listener.stop()
        # 清理LoggerDict池中临时logger对象
        Logger.manager.loggerDict.pop(self.name)


# class DispatcherLogger:
#     def __init__(self, dispatcher_id):
#         self.queue = queue.Queue(-1)
#         self.queue_handler = QueueHandler(self.queue)
#
#         self.name = str(uuid.uuid1())
#         self.logger = logging.getLogger(self.name)
#         self.logger.propagate = False  # 记录消息将不会传递给当前记录器的祖先记录器的处理器
#
#         formatter = logging.Formatter('[%(levelname)s %(asctime)s]:%(message)s')
#         self.dispatcher_log_db_handler = DispatcherLogDBHandler(dispatcher_id)
#         self.dispatcher_log_db_handler.setFormatter(formatter)
#
#         self.logger.addHandler(self.queue_handler)
#         self.listener = QueueListener(self.queue, self.dispatcher_log_db_handler)
#         self.listener.start()
#
#     def close(self):
#         self.listener.stop()
#         # 清理LoggerDict池中临时logger对象
#         Logger.manager.loggerDict.pop(self.name)


if __name__ == '__main__':
    logger = DispatcherLogger()
    logger.logger.warning('这是CaseDispatcherLogger打印日志')
    logger.close()
    print(logger.get_string_buffer())
